<template>
	<view>
	  <u-toast ref="uToast"></u-toast>
	  <view
		v-for="(item, index) in formOptions"
		:key="index"
		:style="{ padding: padding + 'rpx', display: item.hidden ? 'none' : '' }"
		:class="[
		  labelPosition == 'left' ? 'left-form-item' : 'top-form-item',
		  item.type == 'group' ? 'f-form-group' : ''
		]"
		class="f-form-item"
	  >
		<!-- 表单标签 -->
		<view
		  class="f-form-label"
		  v-if="item.type != 'group'"
		  :style="{ maxWidth: labelWidth + 'px', minWidth: '80px' }"
		>
		  <text class="f-form-label-required" v-if="item.require || item.required">*</text>
		  <text>{{ item.title }}</text>
		</view>
  
		<!-- 只读/禁用状态 -->
		<view v-if="item.readonly || item.disabled" style="flex: 1; font-size: 15px; text-align: right">
		  <view v-if="item.type == 'img'" class="readonly-imgs">
			<image
			  v-for="(src, imgIndex) in getImgSrcs(item)"
			  :key="imgIndex"
			  style="width: 70px; height: 70px; margin-left: 20rpx; border-radius: 10rpx"
			  @click="previewImage(item, imgIndex)"
			  :src="src.url"
			></image>
		  </view>
		  <text v-else>{{ formatReadonlyValue(item) }}</text>
		</view>
  
		<!-- 富文本编辑器 -->
		<view v-else-if="item.type == 'editor'">
		  <u-parse :content="formFieldsData[item.field]"></u-parse>
		</view>
  
		<!-- 城市选择器 -->
		<view
		  class="f-form-content f-form-content-select"
		  @click="showCitySheet(item)"
		  v-else-if="item.type == 'city'"
		>
		  <view style="flex: 1">
			<view
			  style="color: rgb(192 196 204); font-size: 15px; padding-right: 12rpx"
			  v-show="isEmpty(formFieldsData[item.field])"
			>
			  {{ '请选择' + item.title }}
			</view>
			<view style="font-size: 15px" v-show="!isEmpty(formFieldsData[item.field])">
			  {{ formFieldsData[item.field]?.replace(/,/g, '') }}
			</view>
		  </view>
		  <u-icon color="rgb(186 186 186)" size="15" name="arrow-right"></u-icon>
		</view>
  
		<!-- 日期选择器 -->
		<template v-else-if="item.type == 'date' || item.type == 'datetime' || item.type == 'month'">
		  <template v-if="item.range">
			<view style="flex: 1" :style="{ 'max-width': item.type == 'date' ? '120rpx' : '30rpx' }"></view>
			<view class="f-form-content f-form-content-select" style="text-align: left" @click="showPicker(item, 0)">
			  <view style="color: rgb(192 196 204); font-size: 15px" v-show="!formFieldsData[item.field]?.[0]">
				开始时间
			  </view>
			  <view style="flex: 1">
				<view style="font-size: 15px">
				  {{
					item.type == 'date'
					  ? (formFieldsData[item.field]?.[0] || '').substr(0, 10)
					  : formFieldsData[item.field]?.[0]
				  }}
				</view>
			  </view>
			</view>
			<text style="margin: 0 0rpx">-</text>
			<view class="f-form-content f-form-content-select" @click="showPicker(item, 1)">
			  <view
				style="color: rgb(192 196 204); font-size: 15px; text-align: right; width: 100%"
				v-show="!formFieldsData[item.field]?.[1]"
			  >
				结束时间
			  </view>
			  <view style="flex: 1">
				<view style="font-size: 15px; text-align: right">
				  {{
					item.type == 'date'
					  ? (formFieldsData[item.field]?.[1] || '').substr(0, 10)
					  : formFieldsData[item.field]?.[1]
				  }}
				</view>
			  </view>
			</view>
		  </template>
		  <view v-else class="f-form-content f-form-content-select" @click="showPicker(item)">
			<view
			  style="color: rgb(192 196 204); font-size: 15px; width: 100%; padding-right: 10rpx"
			  v-show="!formFieldsData[item.field]"
			>
			  {{ '请选择' + item.title }}
			</view>
			<view style="flex: 1">
			  <view style="font-size: 15px; padding-right: 12rpx">
				{{
				  item.type == 'date'
					? (formFieldsData[item.field] || '').substr(0, 10)
					: item.type == 'month'
					? (formFieldsData[item.field] || '').substr(0, 7)
					: formFieldsData[item.field]
				}}
			  </view>
			</view>
			<u-icon color="rgb(186 186 186)" size="15" name="arrow-right"></u-icon>
		  </view>
		</template>
  
		<!-- 数字范围输入 -->
		<template v-else-if="item.range && !['date', 'datetime', 'month'].includes(item.type)">
		  <view style="flex: 1; max-width: 120rpx"></view>
		  <view class="f-form-content f-form-content-select" style="text-align: left">
			<view style="flex: 1">
			  <view style="font-size: 15px">
				<input
				  placeholder-style="color:rgb(192 196 204);font-size:15px;"
				  type="number"
				  v-model="formFieldsData[item.field][0]"
				  border="none"
				  :placeholder="item.placeholder || '请输入' + item.title"
				/>
			  </view>
			</view>
		  </view>
		  <text style="margin: 0 0rpx">-</text>
		  <view class="f-form-content f-form-content-select">
			<input
			  placeholder-style="color:rgb(192 196 204);font-size:15px;"
			  type="number"
			  v-model="formFieldsData[item.field][1]"
			  border="none"
			  :placeholder="item.placeholder || '请输入' + item.title"
			/>
		  </view>
		</template>
  
		<!-- 下拉选择器 -->
		<view
		  class="f-form-content f-form-content-select"
		  @click="showActionSheet(item)"
		  v-else-if="['select', 'selectList', 'checkbox', 'cascader'].indexOf(item.type) != -1"
		>
		  <view style="flex: 1">
			<view
			  style="color: rgb(192 196 204); font-size: 15px; padding-right: 12rpx"
			  v-show="isEmpty(formFieldsData[item.field])"
			>
			  {{ '请选择' + item.title }}
			</view>
			<view style="font-size: 15px" v-show="!isEmpty(formFieldsData[item.field])">
			  {{ formatDicValue(item) }}
			</view>
		  </view>
		  <u-icon color="rgb(186 186 186)" size="15" name="arrow-right"></u-icon>
		</view>
  
		<!-- 分组标题 -->
		<view class="f-form-group-content" :style="item.style" v-else-if="item.type == 'group'">
		  {{ item.title || '' }}
		</view>
  
		<!-- 数字输入 -->
		<view class="f-form-content" v-else-if="item.type == 'number'">
		  <input
			:focus="item.focus"
			placeholder-style="color:rgb(192 196 204);font-size:15px;"
			type="number"
			v-model="formFieldsData[item.field]"
			border="none"
			:placeholder="item.placeholder || '请输入' + item.title"
		  />
		</view>
  
		<!-- 小数输入 -->
		<view class="f-form-content" v-else-if="item.type == 'decimal'">
		  <input
			:focus="item.focus"
			placeholder-style="color:rgb(192 196 204);font-size:15px;"
			type="digit"
			v-model="formFieldsData[item.field]"
			border="none"
			:placeholder="item.placeholder || '请输入' + item.title"
		  />
		</view>
  
		<!-- 单选按钮 -->
		<view class="f-form-content f-form-content-group" v-else-if="item.type == 'radio'">
		  <u-radio-group
			@change="(val: any) => radioOnChange(val, item)"
			:placement="item.placement"
			v-model="formFieldsData[item.field]"
		  >
			<u-radio
			  v-for="(option, opIndex) in item.data"
			  :key="opIndex"
			  :customStyle="{
				'margin-bottom': item.placement == 'column' ? '30rpx' : 0,
				'margin-right': item.placement == 'column' ? '0' : '30rpx'
			  }"
			  :label="option.value"
			  :name="option.key"
			>
			</u-radio>
		  </u-radio-group>
		</view>
  
		<!-- 开关 -->
		<view class="f-form-content f-form-content-group" v-else-if="item.type == 'switch'">
		  <u-radio-group
			@change="(val: any) => radioOnChange(val, item)"
			:placement="item.placement"
			v-model="formFieldsData[item.field]"
			placement="row"
		  >
			<u-radio :customStyle="{ 'margin-right': '40rpx' }" label="是" :name="1"> </u-radio>
			<u-radio label="否" :name="0"> </u-radio>
		  </u-radio-group>
		</view>
  
		<!-- 文本域 -->
		<view class="f-form-content" v-else-if="item.type == 'textarea'">
		  <textarea
			:focus="item.focus"
			auto-height
			style="width: 100%; padding-right: 8rpx"
			:maxlength="item.maxlength || 100000"
			v-model="formFieldsData[item.field]"
			border="none"
			:placeholder="item.placeholder || '请输入' + item.title"
		  ></textarea>
		</view>
  
		<!-- 图片上传 -->
		<u-upload
		  :ref="(el: any) => setUploadRef(item.field, el)"
		  :sizeType="['compressed']"
		  v-else-if="item.type == 'img'"
		  :fileList="formFieldsData[item.field]"
		  @afterRead="(event: any) => afterRead(item, event)"
		  @delete="(event: any) => deletePic(item, event)"
		  name="3"
		  :multiple="item.multiple"
		  :maxCount="item.maxCount || item.maxFile || 1"
		  :previewFullImage="true"
		></u-upload>
  
		<!-- 密码输入 -->
		<view class="f-form-content" v-else-if="item.type == 'password'">
		  <input
			placeholder-style="color:rgb(192 196 204);font-size:15px;"
			type="password"
			v-model="formFieldsData[item.field]"
			border="none"
			:placeholder="item.placeholder || '请输入' + item.title"
		  />
		</view>
  
		<!-- 默认文本输入 -->
		<view class="f-form-content" v-else>
		  <input
			:focus="item.focus"
			placeholder-style="color:rgb(192 196 204);font-size:15px;"
			type="text"
			@confirm="(e: any) => inputConfirm(item.field, e)"
			v-model="formFieldsData[item.field]"
			border="none"
			:placeholder="item.placeholder || '请输入' + item.title"
		  />
		</view>
  
		<!-- 额外操作 -->
		<view
		  v-if="item.extra"
		  :style="item.extra.style"
		  style="display: flex"
		  @click="extraClick(item, formFieldsData)"
		>
		  <u-icon v-if="item.extra.icon" :name="item.extra.icon" :color="item.extra.color" :size="item.extra.size">
		  </u-icon>
		  <text>{{ item.extra.text }}</text>
		</view>
	  </view>
	  <slot></slot>
  
	  <!-- 日期选择器弹窗 -->
	  <u-datetime-picker
		class="form-popup"
		:minDate="pickerCurrentItem.min"
		:maxDate="pickerCurrentItem.max"
		:zIndex="9999999"
		:closeOnClickOverlay="true"
		:show="pickerModel"
		:value="pickerValue"
		:mode="pickerCurrentItem.type == 'month' ? 'year-month' : pickerCurrentItem.type"
		closeOnClickOverlay
		@confirm="pickerConfirm"
		@cancel="pickerClose"
		@close="pickerClose"
	  ></u-datetime-picker>
  
	  <!-- 下拉选择弹窗 -->
	  <u-popup
		@touchmove.prevent
		class="form-popup"
		:zIndex="999999"
		:show="actionSheetModel"
		@close="actionSheetModel = false"
	  >
		<view class="vol-action-sheet-select-container" :style="{ height: popupHeight + 'px' }">
		  <view class="vol-action-sheet-select-title"
			>请选择{{ actionSheetCurrentItem.title }}
			<text class="vol-action-sheet-select-confirm" @click="actionConfirmClick">确定</text>
		  </view>
		  <!-- 搜索框 -->
		  <view v-if="showFilter" class="vol-action-sheet-select-filter">
			<u-search
			  @custom="searchText = ''"
			  placeholder="请输入关键字搜索"
			  :showAction="true"
			  actionText="清除"
			  :animation="false"
			  v-model="searchText"
			>
			</u-search>
		  </view>
		  <!-- 选项列表 -->
		  <view class="vol-action-sheet-select-content">
			<view
			  :class="{ 'vol-action-sheet-select-actived': actionSheetModel && isActionSelected(item) }"
			  @click="actionClick(item)"
			  v-show="!item.hidden && (!searchText || item.value.indexOf(searchText) != -1)"
			  :key="index"
			  v-for="(item, index) in actionSheetCurrentItem.data"
			  class="vol-action-sheet-select-item"
			>
			  {{ item.value }}
			</view>
		  </view>
		</view>
	  </u-popup>
  
	  <!-- 树形级联组件 -->
	  <vol-tree
		ref="cascaderRef"
		:data="cascaderData"
		:title="'请选择' + cascaderTitle"
		:checkStrictly="cascaderCheckStrictly"
		@cancel="cascaderCancel"
		@confirm="cascaderConfirm"
	  >
	  </vol-tree>
  
	  <!-- 城市选择组件 -->
	  <lotus-address v-on:choseVal="onCitySelect" :lotusAddressData="lotusAddressData"></lotus-address>
	</view>
  </template>
  
  <script setup lang="ts">
  import { ref, reactive, computed, watch, onMounted, nextTick } from 'vue'
  import { onLoad } from '@dcloudio/uni-app'
  import lotusAddress from './../Winglau14-lotusAddress/Winglau14-lotusAddress.vue'
  import { useToast } from '@/composables/useToast'
  import { useHttp } from '@/composables/useHttp'
  import { useStore } from '@/store'
  import type { FormOption, FormField, DictionaryItem, UploadFile, CascaderItem } from '@/types/form'
  
  // Props定义
  interface Props {
	formOptions: FormOption[]
	formFields: Record<string, any>
	padding?: number
	labelWidth?: number
	labelPosition?: 'left' | 'top'
	loadKey?: boolean
	uploadBefore?: (files: UploadFile[], option: FormOption) => boolean | Promise<boolean>
  }
  
  const props = withDefaults(defineProps<Props>(), {
	padding: 30,
	labelWidth: 150,
	labelPosition: 'left',
	loadKey: true,
	uploadBefore: () => true
  })
  
  // Emits定义
  interface Emits {
	(e: 'update:formFields', value: Record<string, any>): void
	(e: 'dicInited', value: DictionaryItem[]): void
	(e: 'onChange', field: string, value: any, item?: FormOption, data?: any): void
	(e: 'extraClick', item: FormOption, formFields: Record<string, any>): void
	(e: 'input-confirm', field: string, event: any): void
  }
  
  const emit = defineEmits<Emits>()
  
  // 组合式函数
  const { showToast } = useToast()
  const http = useHttp()
  const store = useStore()
  
  // 响应式数据
  const formFieldsData = ref<Record<string, any>>({})
  const searchText = ref('')
  const showFilter = ref(false)
  const maxHeight = ref(400)
  const popupHeight = ref(0)
  
  // 日期选择器相关
  const pickerValue = ref('')
  const pickerModel = ref(false)
  const pickerCurrentItem = ref<any>({})
  const pickerCurrentRangeIndex = ref(0)
  
  // 下拉选择相关
  const actionSheetModel = ref(false)
  const actionSheetCurrentItem = ref<any>({
	min: 633715200000,
	max: 0,
	data: []
  })
  const actionSheetSelectValues = ref<any[]>([])
  
  // 级联选择相关
  const cascaderRef = ref()
  const cascaderData = ref<CascaderItem[]>([])
  const cascaderTitle = ref('')
  const cascaderCheckStrictly = ref(false)
  const cascaderField = ref('')
  
  // 城市选择相关
  const lotusAddressData = reactive({
	visible: false,
	provinceName: '',
	cityName: '',
	townName: ''
  })
  const cityItem = ref<FormOption>({ field: '' } as FormOption)
  
  // 图片字段
  const imgFields = ref<string[]>([])
  
  // Refs管理
  const uploadRefs = ref<Record<string, any>>({})
  
  // 设置上传组件ref
  const setUploadRef = (field: string, el: any) => {
	if (el) {
	  uploadRefs.value[field] = el
	}
  }
  
  // 初始化
  onMounted(() => {
	initFormData()
	loadDictionary()
	getSystemInfo()
  })
  
  // 初始化表单数据
  const initFormData = () => {
	// 处理日期选项的最小最大值
	props.formOptions.forEach(option => {
	  if (['date', 'datetime', 'month'].includes(option.type)) {
		if (!option.min) {
		  option.min = Number(new Date('1990/01/01 00:00:00'))
		} else if (typeof option.min === 'string') {
		  if (option.type === 'month' && option.min.length !== 7) {
			option.min = option.min.substring(0, 7)
		  }
		  option.min = Number(new Date(option.min.replace(/-/g, '/')))
		}
		if (!option.max) {
		  option.max = Number(new Date(new Date().getFullYear() + 10 + '/01/01 00:00:00'))
		} else if (option.max && typeof option.max === 'string') {
		  option.max = Number(new Date(option.max.replace(/-/g, '/')))
		}
	  }
  
	  if (option.hasOwnProperty('focus')) {
		option.focus = false
	  }
	})
  
	// 初始化表单字段
	formFieldsData.value = { ...props.formFields }
  
	// 处理图片字段
	imgFields.value = props.formOptions.filter(x => x.type === 'img').map(x => x.field)
	if (imgFields.value.length) {
	  convertImgArr(formFieldsData.value)
	}
  }
  
  // 加载字典数据
  const loadDictionary = async () => {
	if (!props.loadKey) return
  
	const dicKeys = props.formOptions
	  .filter(x => x.key || x.dataKey)
	  .map(m => m.key || m.dataKey)
  
	if (!dicKeys.length) return
  
	try {
	  const result = await http.post('api/Sys_Dictionary/GetVueDictionary', dicKeys, true)
	  initDataSource(result)
	} catch (error) {
	  console.error('加载字典失败:', error)
	}
  }
  
  // 初始化数据源
  const initDataSource = (result: any[]) => {
	result.forEach(res => {
	  props.formOptions.forEach(option => {
		if ((option.key || option.dataKey) === res.dicNo) {
		  option.data = res.data
		}
	  })
	})
	emit('dicInited', result)
  }
  
  // 获取系统信息
  const getSystemInfo = () => {
	uni.getSystemInfo({
	  success: (res) => {
		maxHeight.value = res.screenHeight * 0.85
	  }
	})
  }
  
  // 工具函数
  const isEmpty = (value: any, includeZero = false): boolean => {
	if (value === null || value === undefined || value === '') return true
	if (includeZero && value === 0) return true
	if (Array.isArray(value) && value.length === 0) return true
	return false
  }
  
  // 转换图片数组
  const convertImgArr = (formFields: Record<string, any>) => {
	if (!imgFields.value.length) return
  
	imgFields.value.forEach(field => {
	  if (!Array.isArray(formFields[field])) {
		if (isEmpty(formFields[field])) {
		  formFields[field] = []
		} else {
		  formFields[field] = formFields[field].split(',').map((x: string) => ({
			url: http.ipAddress + x,
			orginUrl: x
		  }))
		}
	  }
	})
  }
  
  // 显示日期选择器
  const showPicker = (item: FormOption, index?: number) => {
	pickerCurrentItem.value = item
	let val = formFieldsData.value[item.field]
  
	if (item.range) {
	  pickerCurrentRangeIndex.value = index || 0
	  if (!Array.isArray(val)) {
		formFieldsData.value[item.field] = ['', '']
		val = ['', '']
	  }
	  val = val[index || 0]
	}
  
	if (!val) {
	  const now = new Date()
	  if (item.type === 'date') {
		val = formatDate(now, 'yyyy-mm-dd')
	  } else if (item.type === 'month') {
		val = formatDate(now, 'yyyy-mm')
	  } else {
		val = formatDate(now, 'yyyy-mm-dd hh:MM')
	  }
	}
  
	pickerValue.value = Number(new Date(val.replace(/-/g, '/')))
	pickerModel.value = true
	hideKeyboard()
  }
  
  // 日期确认
  const pickerConfirm = (e: any) => {
	pickerModel.value = false
	
	let value: string
	if (typeof e.value === 'number') {
	  const format = pickerCurrentItem.value.type === 'date' ? 'yyyy-mm-dd' : 'yyyy-mm-dd hh:MM'
	  value = uni.$u.timeFormat(e.value, format)
	} else {
	  value = uni.$u.timeFormat(e.value)
	}
  
	setPickerValue(value)
  }
  
  // 设置日期值
  const setPickerValue = (value: string) => {
	if (pickerCurrentItem.value.range) {
	  formFieldsData.value[pickerCurrentItem.value.field][pickerCurrentRangeIndex.value] = value
	} else {
	  formFieldsData.value[pickerCurrentItem.value.field] = value
	}
	emit('onChange', pickerCurrentItem.value.field, value)
  }
  
  // 日期选择器关闭
  const pickerClose = () => {
	pickerModel.value = false
  }
  
  // 显示下拉选择
  const showActionSheet = (item: FormOption) => {
	if (item.type === 'cascader') {
	  cascaderField.value = item.field
	  cascaderData.value = [...(item.data || [])]
	  cascaderTitle.value = item.title
	  cascaderCheckStrictly.value = item.checkStrictly || false
	  cascaderRef.value?.show(formFieldsData.value[item.field])
	  return
	}
  
	searchText.value = ''
	actionSheetSelectValues.value = []
	actionSheetCurrentItem.value = item
  
	const value = formFieldsData.value[item.field]
	if (!isEmpty(value)) {
	  if (Array.isArray(value)) {
		actionSheetSelectValues.value = [...value]
	  } else if (isMultiSelect(item)) {
		actionSheetSelectValues.value = value.split(',')
	  } else {
		actionSheetSelectValues.value = [value]
	  }
	}
  
	showFilter.value = item.data?.length > 15
	const height = ((item.data?.length || 0) + 1 + (showFilter.value ? 1 : 0)) * 50
	popupHeight.value = height > maxHeight.value ? maxHeight.value : height
	actionSheetModel.value = true
  }
  
  // 下拉选项点击
  const actionClick = (item: any) => {
	if (isMultiSelect()) {
	  const key = String(item.key)
	  if (isActionSelected(item)) {
		actionSheetSelectValues.value = actionSheetSelectValues.value.filter(x => String(x) !== key)
	  } else {
		actionSheetSelectValues.value.push(item.key)
	  }
	  return
	}
  
	formFieldsData.value[actionSheetCurrentItem.value.field] = item.key
	actionSheetModel.value = false
	emit('onChange', actionSheetCurrentItem.value.field, formFieldsData.value[actionSheetCurrentItem.value.field], item)
  }
  
  // 判断是否多选
  const isMultiSelect = (item?: FormOption): boolean => {
	const type = item?.type || actionSheetCurrentItem.value.type
	return ['checkbox', 'selectList'].includes(type)
  }
  
  // 判断选项是否已选中
  const isActionSelected = (item: any): boolean => {
	return actionSheetSelectValues.value.some(x => String(x) === String(item.key))
  }
  
  // 下拉确认
  const actionConfirmClick = () => {
	if (!isMultiSelect()) {
	  actionSheetModel.value = false
	  return
	}
  
	if (Array.isArray(formFieldsData.value[actionSheetCurrentItem.value.field])) {
	  formFieldsData.value[actionSheetCurrentItem.value.field] = [...actionSheetSelectValues.value]
	} else {
	  formFieldsData.value[actionSheetCurrentItem.value.field] = actionSheetSelectValues.value.join(',')
	}
	actionSheetModel.value = false
  }
  
  // 格式化字典值
  const formatDicValue = (item: FormOption): string => {
	const value = formFieldsData.value[item.field]
	if (isEmpty(value)) return ''
  
	if (item.type === 'cascader') {
	  return getCascaderNames(value, item)
	}
  
	if (isMultiSelect(item)) {
	  return formatDicValueList(item)
	}
  
	const kv = item.data?.find(x => String(x.key) === String(value))
	return kv?.value || value
  }
  
  // 格式化多选值
  const formatDicValueList = (item: FormOption): string => {
	const value = formFieldsData.value[item.field]
	if (isEmpty(value)) return ''
  
	const values = Array.isArray(value) ? value : String(value).split(',')
	const textArr: string[] = []
  
	values.forEach(x => {
	  const obj = item.data?.find(c => String(x) === String(c.key))
	  textArr.push(obj?.value || x)
	})
  
	return textArr.join(',')
  }
  
  // 获取级联名称
  const getCascaderNames = (value: any, item: FormOption): string => {
	const ids = getAllParentId(value, item.data || [])
	const names: string[] = []
  
	ids.forEach(id => {
	  const obj = item.data?.find(x => x.id === id)
	  names.push(obj?.value || obj?.name || id)
	})
  
	return names.join('/')
  }
  
  // 获取所有父级ID
  const getAllParentId = (id: any, data: any[]): any[] => {
	if (id === null || id === '' || id === undefined) return []
  
	const isString = data.some(x => typeof x.id === 'string')
	id = isString ? String(id) : Number(id)
  
	const ids = [id]
	for (let index = 0; index < ids.length; index++) {
	  const node = data.find(x => x.id === ids[index])
	  if (!node || node.parentId === null || node.parentId === undefined) {
		return ids
	  }
	  if (data.some(x => x.id === node.parentId)) {
		ids.push(node.parentId)
	  }
	}
  
	return ids.reverse()
  }
  
  // 级联确认
  const cascaderConfirm = (value: any, item: any) => {
	formFieldsData.value[cascaderField.value] = value
	emit('onChange', cascaderField.value, value, item)
  }
  
  // 级联取消
  const cascaderCancel = () => {
	// 处理取消逻辑
  }
  
  // 显示城市选择
  const showCitySheet = (item: FormOption) => {
	cityItem.value = item
	const arr = (formFieldsData.value[item.field] || '').split(',')
	lotusAddressData.provinceName = arr[0] || ''
	lotusAddressData.cityName = arr[1] || ''
	lotusAddressData.townName = arr[2] || ''
	lotusAddressData.visible = true
  }
  
  // 城市选择回调
  const onCitySelect = (res: any) => {
	lotusAddressData.visible = res.visible
	if (res.isChose) {
	  lotusAddressData.provinceName = res.province
	  lotusAddressData.cityName = res.city
	  lotusAddressData.townName = res.town
	  formFieldsData.value[cityItem.value.field] = `${res.province},${res.city},${res.town}`
	}
  }
  
  // 图片上传
  const afterRead = async (option: FormOption, event: any) => {
	if (!option.url) {
	  return showToast('未配置好url')
	}
  
	let lists = []
	if (option.multiple) {
	  lists = [].concat(event.file)
	} else {
	  lists = Array.isArray(event.file) ? [...event.file] : [event.file]
	}
  
	const fileListLen = formFieldsData.value[option.field].length
	lists.forEach(item => {
	  formFieldsData.value[option.field].push({
		...item,
		status: 'uploading',
		message: '上传中'
	  })
	})
  
	for (let i = 0; i < lists.length; i++) {
	  try {
		const result = await uploadFilePromise(lists[i].url, option.url)
		const item = formFieldsData.value[option.field][fileListLen + i]
		let fileName = lists[i].name
  
		if (!fileName && lists[i].thumb) {
		  const lastIndex = lists[i].thumb.lastIndexOf('/') + 1
		  fileName = lists[i].thumb.substr(lastIndex)
		}
  
		formFieldsData.value[option.field].splice(fileListLen + i, 1, {
		  ...item,
		  status: 'success',
		  message: '',
		  url: http.ipAddress + result + fileName,
		  orginUrl: result + fileName
		})
	  } catch (error) {
		console.error('上传失败:', error)
	  }
	}
  }
  
  // 上传文件Promise
  const uploadFilePromise = (url: string, apiUrl: string): Promise<string> => {
	return new Promise((resolve, reject) => {
	  uni.uploadFile({
		url: http.ipAddress + apiUrl,
		filePath: url,
		name: 'fileInput',
		header: {
		  uapp: 1,
		  Authorization: store.getters.getToken()
		},
		formData: {},
		success: (res) => {
		  setTimeout(() => {
			resolve(JSON.parse(res.data).data)
		  }, 500)
		},
		fail: (res) => {
		  showToast('上传失败')
		  reject(res)
		}
	  })
	})
  }
  
  // 删除图片
  const deletePic = (item: FormOption, event: any) => {
	formFieldsData.value[item.field].splice(event.index, 1)
  }
  
  // 获取图片源
  const getImgSrcs = (item: FormOption): any[] => {
	const imgs = formFieldsData.value[item.field]
	if (!imgs) return []
	if (Array.isArray(imgs)) return imgs
  
	const imgArr = imgs.split(',')
	return imgArr.filter((x: string) => x).map((m: string) => ({ url: m }))
  }
  
  // 预览图片
  const previewImage = (item: FormOption, imgIndex: number) => {
	const imgs = getImgSrcs(item).map(x => x.url)
	uni.previewImage({
	  urls: imgs,
	  current: imgIndex
	})
  }
  
  // 格式化只读值
  const formatReadonlyValue = (item: FormOption): string => {
	if (item.data) {
	  return formatDicValue(item)
	}
	if (item.type === 'date') {
	  return (formFieldsData.value[item.field] || '').substr(0, 10)
	}
	return formFieldsData.value[item.field] || ''
  }
  
  // 输入确认
  const inputConfirm = (field: string, e: any) => {
	emit('input-confirm', field, e)
  }
  
  // 单选改变
  const radioOnChange = (value: any, item: FormOption) => {
	emit('onChange', item.field, value, item, item.data)
  }
  
  // 额外点击
  const extraClick = (item: FormOption, formFields: Record<string, any>) => {
	emit('extraClick', item, formFields)
  }
  
  // 隐藏键盘
  const hideKeyboard = () => {
	uni.hideKeyboard()
  }
  
  // 格式化日期
  const formatDate = (date: Date, format: string): string => {
	const year = date.getFullYear()
	const month = String(date.getMonth() + 1).padStart(2, '0')
	const day = String(date.getDate()).padStart(2, '0')
	const hours = String(date.getHours()).padStart(2, '0')
	const minutes = String(date.getMinutes()).padStart(2, '0')
  
	return format
	  .replace('yyyy', String(year))
	  .replace('mm', month)
	  .replace('dd', day)
	  .replace('hh', hours)
	  .replace('MM', minutes)
  }
  
  // 表单验证
  const validate = (): boolean => {
	const option = props.formOptions
	  .filter(c => c.require || c.required)
	  .find(x => {
		const val = formFieldsData.value[x.field]
		if (Array.isArray(val)) {
		  return !val.length
		}
		return isEmpty(val)
	  })
  
	if (option) {
	  const needSelectTypes = ['date', 'datetime', 'month', 'checkbox', 'select', 'selectList', 'radio', 'switch']
	  if (needSelectTypes.includes(option.type)) {
		showToast(`请选择${option.title}`)
	  } else {
		showToast(`${option.title}不能为空`)
	  }
	  return false
	}
	return true
  }
  
  // 重置表单
  const reset = (source?: Record<string, any>) => {
	Object.keys(formFieldsData.value).forEach(key => {
	  if (source && source.hasOwnProperty(key)) {
		formFieldsData.value[key] = source[key]
	  } else {
		if (Array.isArray(formFieldsData.value[key])) {
		  formFieldsData.value[key] = []
		  const option = props.formOptions.find(x => x.field === key)
		  if (option?.range) {
			formFieldsData.value[key] = ['', '']
		  }
		} else {
		  formFieldsData.value[key] = ''
		}
	  }
	})
  }
  
  // 监听表单数据变化
  watch(
	formFieldsData,
	(val) => {
	  if (val && Object.keys(val).length) {
		emit('update:formFields', val)
	  }
	},
	{ deep: true }
  )
  
  // 监听props变化
  watch(
	() => props.formFields,
	(val) => {
	  convertImgArr(val)
	  formFieldsData.value = { ...val }
	},
	{ deep: true }
  )
  
  // 暴露方法
  defineExpose({
	validate,
	reset,
	hideKeyboard
  })